package com.mushuilingfeng.ddd.user.domain.org.entity;

import cn.hutool.core.util.StrUtil;
import com.mushuilingfeng.ddd.user.domain.base.BaseEntity;
import com.mushuilingfeng.ddd.user.domain.base.BusinessException;
import com.mushuilingfeng.ddd.user.domain.base.Ii8nCode;
import com.mushuilingfeng.ddd.user.domain.base.GenderEnum;
import com.mushuilingfeng.ddd.user.domain.base.StatusEnum;
import com.mushuilingfeng.ddd.user.domain.org.repository.IDepartmentRepository;
import com.mushuilingfeng.ddd.user.domain.org.repository.IEmployeeRepository;
import com.mushuilingfeng.ddd.user.domain.org.repository.IOrgRepository;
import com.mushuilingfeng.ddd.user.domain.org.service.IDepartmentService;
import com.mushuilingfeng.ddd.user.domain.org.vo.Contact;
import com.mushuilingfeng.ddd.user.domain.user.entity.User;
import com.mushuilingfeng.ddd.framework.factory.DomainServiceFactory;
import com.mushuilingfeng.ddd.framework.factory.DomainRepositoryFactory;
import lombok.Data;
import lombok.EqualsAndHashCode;

import java.util.Date;

/**
 * 部门
 *
 * @author
 * @date 2024/9/14
 */
@EqualsAndHashCode(callSuper = true)
@Data
public class Department extends BaseEntity {
    private String deptCode;
    private String deptName;
    private String parentDeptCode;
    private String orgCode;
    private Date setUpTime;
    private Integer status;
    private Integer deptLevel;
    private Integer employeeCount;

    public void setDeptLevel(Integer deptLevel) {
        if (null != this.deptLevel) {
            throw new IllegalArgumentException("deptLevel已经有值，不能重复设置！");
        }
    }

    @Override
    public void saveNew() {
        if (StrUtil.isBlankIfStr(orgCode)) {
            throw new IllegalArgumentException("所属机构编码不能为空！");
        }
        if (StrUtil.isBlankIfStr(deptName)) {
            throw new IllegalArgumentException("部门名称不能为空！");
        }
        super.saveNew();
        if (null != setUpTime) {
            setSetUpTime(new Date());
        }
        if (null == this.deptLevel) {
            setDeptLevel(1);
        }
        if (null == deptCode) {
            setDeptCode(DomainServiceFactory.getDomainService(IDepartmentService.class).newDeptCode());
        }
        setStatus(StatusEnum.OPEN.getCode());
        setEmployeeCount(0);
        DomainRepositoryFactory.getRepository(IDepartmentRepository.class).saveOrUpdate(this);
    }

    @Override
    public void delete() {
        if (employeeCount > 0) {
            throw new BusinessException(Ii8nCode.DEPT_EMPLOYEE_NOT_EMPTY);
        }
        IDepartmentRepository departmentRepository = DomainRepositoryFactory.getRepository(IDepartmentRepository.class);
        if (departmentRepository.existChildDept(deptCode)) {
            throw new BusinessException(Ii8nCode.DEPT_NOT_EMPTY);
        }
        departmentRepository.delete(id);
    }

    public Org getOrg() {
        return DomainRepositoryFactory.getRepository(IOrgRepository.class).getByOrgCode(orgCode);
    }

    public Department getParentDept() {
        if (StrUtil.isBlankIfStr(parentDeptCode)) {
            return null;
        }
        return DomainRepositoryFactory.getRepository(IDepartmentRepository.class).getByDeptCode(parentDeptCode);
    }

    private void checkDeptStatus() {
        if (status != StatusEnum.OPEN.getCode()) {
            throw new BusinessException(Ii8nCode.DEPT_STATUS_NOT_OPEN);
        }
    }

    /**
     * 添加子部门
     *
     * @param childDepartment 子部门
     */
    public void addChildDept(Department childDepartment) {
        checkDeptStatus();
        if (deptLevel <= 2) {
            throw new BusinessException(Ii8nCode.DEPT_LEVEL_NOT_ALLOWED);
        }
        childDepartment.setDeptLevel(deptLevel + 1);
        childDepartment.setParentDeptCode(deptCode);
        childDepartment.setOrgCode(orgCode);
        childDepartment.saveNew();
    }

    /**
     * 移除子部门
     *
     * @param childDeptCode 子部门
     */
    public void removeChildDept(String childDeptCode) {
        checkDeptStatus();
        IDepartmentRepository departmentRepository = DomainRepositoryFactory.getRepository(IDepartmentRepository.class);
        // 判断子部门下面是否还有子部门
        Department childDept = departmentRepository.getByDeptCode(childDeptCode);
        if (childDept == null) {
            throw new BusinessException(Ii8nCode.DEPT_NOT_EXIST);
        }
        if (!deptCode.equals(childDept.getParentDeptCode())) {
            throw new BusinessException(Ii8nCode.DEPT_IS_NOT_TARGET_CHILD);
        }
        childDept.delete();
    }

    public void addEmployee(User user) {
        checkDeptStatus();
        Employee employee = new Employee();
        employee.setOrgCode(orgCode);
        employee.setDeptCode(deptCode);
        employee.setEmployeeName(user.getNickName());
        employee.setGender(user.getGender());
        employee.setContact(Contact.builder().tel(user.getTelephone()).build());
        employee.setJoinTime(new Date());
        employee.saveNew();
        employeeCount++;
        DomainRepositoryFactory.getRepository(IDepartmentRepository.class).incrementEmployeeCount(deptCode, 1);
    }

    public void addEmployee(String employeeName, GenderEnum gender, Contact contact) {
        checkDeptStatus();
        Employee employee = new Employee();
        employee.setOrgCode(orgCode);
        employee.setDeptCode(deptCode);
        employee.setEmployeeName(employeeName);
        employee.setGender(gender);
        employee.setContact(contact);
        employee.setJoinTime(new Date());
        employee.saveNew();
        employeeCount++;
        DomainRepositoryFactory.getRepository(IDepartmentRepository.class).incrementEmployeeCount(deptCode, 1);
    }

    public void removeEmployee(String employeeCode) {
        checkDeptStatus();
        Employee employee = DomainRepositoryFactory.getRepository(IEmployeeRepository.class).getByEmployeeCode(employeeCode);
        if (null == employee) {
            throw new BusinessException(Ii8nCode.EMPLOYEE_NOT_EXIST);
        }
        if (!deptCode.equals(employee.getDeptCode())) {
            throw new BusinessException(Ii8nCode.DEPT_IS_NOT_TARGET_EMPLOYEE);
        }
        employee.delete();
        DomainRepositoryFactory.getRepository(IDepartmentRepository.class).incrementEmployeeCount(deptCode, -1);
    }

}
